/**
 * Copyright © 2011 Creativor Studio.
 * About license information, please see LICENSE.txt.
 */

package org.creativor.rayson.client.shell;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.URI;
import java.util.HashMap;
import java.util.StringTokenizer;

/**
 * This object is used to invoke a RPC call.
 * 
 * @author Nick Zhang
 */
class RpcInvoker
{
	private static final HashMap<SocketAddress, ServerAgent> SERVERS =
			new HashMap<SocketAddress, ServerAgent>();
	
	private String methodName;
	
	private String parameters;
	
	private InetSocketAddress serverAddress;
	
	private String serviceName;
	
	/**
	 * 
	 * @param path
	 * @param parameters
	 */
	public RpcInvoker(URI path, String parameters)
	{
		if (path == null) throw new IllegalArgumentException("Uri should not be null");
		this.serverAddress = new InetSocketAddress(path.getHost(), path.getPort());
		String fullPath = path.getPath();
		StringTokenizer tokenizer = new StringTokenizer(fullPath, "/");
		if (tokenizer.countTokens() != 2)
			throw new IllegalArgumentException("Uri path length must be 2");
		this.serviceName = tokenizer.nextToken();
		this.methodName = tokenizer.nextToken();
		this.parameters = "[" + parameters + "]";
		
	}
	
	/**
	 * @param serverAddress
	 * @return
	 */
	private ServerAgent getOrCreateServerAgent(InetSocketAddress serverAddress)
	{
		ServerAgent serverAgent = SERVERS.get(serverAddress);
		if (serverAgent == null)
		{
			serverAgent = new ServerAgent(serverAddress);
			SERVERS.put(serverAddress, serverAgent);
		}
		return serverAgent;
	}
	
	/**
	 * Command call parameters. Not including first ( and last ). <br>
	 * Format: [parameter1_json, parameter2_json].
	 */
	public String getParameters()
	{
		return parameters;
	}
	
	/**
	 * Return the result of invoke the associated RPC call.
	 * 
	 * @throws RpcInvokeException
	 */
	public String invoke() throws RpcInvokeException
	{
		// Find server.
		ServerAgent serverAgent = getOrCreateServerAgent(serverAddress);
		return serverAgent.invoke(this.serviceName, this.methodName, this.parameters);
	}
	
	@Override
	public String toString()
	{
		StringBuffer sb = new StringBuffer();
		sb.append("{");
		sb.append("server: ");
		sb.append(this.serverAddress.toString());
		sb.append(", ");
		sb.append("serviceName: ");
		sb.append(this.serviceName);
		sb.append(", ");
		sb.append("method: ");
		sb.append(this.methodName);
		sb.append(", ");
		sb.append("parameters: ");
		sb.append(this.parameters);
		sb.append("}");
		return sb.toString();
	}
}
